﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq.Expressions;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Validation;
using GMS.Framework.Contract;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Reflection;
using System.Data;
using System.Collections;

namespace GMS.Framework.DAL
{
    /// <summary>
    /// DAL基类，实现Repository通用泛型数据访问模式
    /// </summary>
    public class DbContextBase : DbContext, IDataRepository, IDisposable
    {
        /// <summary>
        /// 构造方法，初始化context
        /// </summary>
        public DbContextBase(string connectionString)
        {

            Database.Connection.ConnectionString = connectionString;
            Configuration.LazyLoadingEnabled = false;
            Configuration.ProxyCreationEnabled = false;
        }

        /// <summary>
        /// 构造方法，增加监听器
        /// </summary>
        public DbContextBase(string connectionString, IAuditable auditLogger)
            : this(connectionString)
        {
            AuditLogger = auditLogger;
        }

        /// <summary>
        /// 监听器
        /// </summary>
        public IAuditable AuditLogger { get; set; }

        /// <summary>
        /// 更新到数据库
        /// </summary>
        public T Update<T>(T entity) where T : ModelBase
        {
            var set = Set<T>();
            set.Attach(entity);
            Entry(entity).State = EntityState.Modified;
            SaveChanges();

            return entity;
        }

        /// <summary>
        /// 生成更新实体的sql但不操作数据库
        /// </summary>
        public T UpdateNotSaveChanges<T>(T entity) where T : ModelBase
        {
            var set = Set<T>();
            set.Attach(entity);
            foreach (var p in entity.GetType().GetProperties())
            {
                if (p.GetValue(entity) != null)
                {
                    try
                    {
                        Entry(entity).Property(p.Name).IsModified = true;
                    }
                    catch (Exception)
                    {
                        continue;
                    }
                }
            }
            return entity;
        }

        /// <summary>
        /// 生成插入sql并执行到数据库返回结果
        /// </summary>
        public T Insert<T>(T entity) where T : ModelBase
        {
            Set<T>().Add(entity);
            SaveChanges();
            return entity;
        }

        /// <summary>
        /// 批量插入数据
        /// </summary>
        public int BatchInsert<T>(List<T> list) where T : ModelBase
        {
            Set<T>().AddRange(list);
            SaveChanges();
            return list.Count;
        }

        /// <summary>
        /// 生成插入实体的sql但不操作数据库
        /// </summary>
        public T InsertNotSaveChanges<T>(T entity) where T : ModelBase
        {
            Set<T>().Add(entity);
            return entity;
        }

        /// <summary>
        /// 生成删除sql并执行到数据库
        /// </summary>
        public void Delete<T>(T entity) where T : ModelBase
        {
            Entry(entity).State = EntityState.Deleted;
            SaveChanges();
        }

        /// <summary>
        /// 根据主键查找对应的值，找不到对应的值就返回null
        /// </summary>
        public T Find<T>(params object[] keyValues) where T : ModelBase
        {
            return Set<T>().Find(keyValues);
        }

        /// <summary>
        /// 根据兰姆达表达式的条件查找对应的值
        /// </summary>
        public List<T> FindAll<T>(Expression<Func<T, bool>> conditions = null) where T : ModelBase
        {
            if (conditions == null)
                return Set<T>().ToList();
            return Set<T>().Where(conditions).ToList();
        }

        /// <summary>
        /// 更新操作到数据库
        /// </summary>
        public override int SaveChanges()
        {
            WriteAuditLog();

            var result = base.SaveChanges();
            return result;
        }

        /// <summary>
        /// 记录操作日志到数据库
        /// </summary>
        internal void WriteAuditLog()
        {
            if (AuditLogger == null)
                return;

            foreach (var dbEntry in ChangeTracker.Entries<ModelBase>().Where(p => p.State == EntityState.Added || p.State == EntityState.Deleted || p.State == EntityState.Modified))
            {
                var auditableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(AuditableAttribute), false).SingleOrDefault() as AuditableAttribute;
                if (auditableAttr == null)
                    continue;

                var operaterName = string.Empty;
                if (WCFContext.Current.Count > 0)
                {
                    operaterName = WCFContext.Current.Operater.Name;
                }
                var t = Task.Factory.StartNew(() =>
                {
                    var tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), false)
                        .SingleOrDefault() as TableAttribute;
                    var tableName = tableAttr != null ? tableAttr.Name : dbEntry.Entity.GetType().Name;
                    var moduleName = dbEntry.Entity.GetType().FullName.Split('.').Skip(1).FirstOrDefault();
                    AuditLogger.WriteLog(dbEntry.Entity.ID, operaterName, moduleName, tableName, dbEntry.State.ToString(), dbEntry.Entity);
                });
                t.Wait();
            }
        }

        protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
        {
            //当实体不为null且实体状态为已发生变化时执行
            if (entityEntry != null && entityEntry.State == EntityState.Modified)
            {
                //获取实体验证结果
                var ValidateEntity = base.ValidateEntity(entityEntry, items);
                //获取实体当前属性的属性名称列表
                var PropertyNames = ValidateEntity.Entry.CurrentValues.PropertyNames;

                foreach (var PropertyName in PropertyNames)
                {
                    //判断当前属性的值是否发生了变化
                    if (ValidateEntity.Entry.Property(PropertyName).IsModified == false)
                    {
                        //如果当前实体属性未发生变化，则查询验证结果中该属性的验证错误信息
                        var ve = ValidateEntity.ValidationErrors.FirstOrDefault(a => a.PropertyName == PropertyName);
                        //如果获取的该实体当前属性的验证错误信息存在，则从验证错误信息中移除它
                        if (ve != null)
                        {
                            ValidateEntity.ValidationErrors.Remove(ve);
                        }
                    }
                }
                //返回最终的验证结果
                return ValidateEntity;
            }
            else
            {
                return base.ValidateEntity(entityEntry, items);
            }

        }
    }
}
